﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;

namespace Hinacom.Scheduler.Manager.Utilities
{
    /// <summary>
    /// 处理控件和数据的绑定
    /// </summary>
    public abstract class ControlDataBinder
    {
        /// <summary>
        /// 从控件收集数据填到指定的对象中
        /// </summary>
        /// <param name="entity">控件的数据会填到此对象中</param>
        /// <param name="maps">控件和属性的对应关系</param>
        public static void CollectControlData(object entity, params ControlDataMap[] maps)
        {
            Type t = entity.GetType();
            foreach (ControlDataMap map in maps)
            {
                object v = null;
                if (map.Control is TextBoxBase)
                    v = ((TextBoxBase)map.Control).Text;
                else if (map.Control is CheckBox)
                    v = ((CheckBox)map.Control).Checked;
                else if (map.Control is NumericUpDown)
                {
                    Type propertyType = t.GetProperty(map.Property).PropertyType;
                    if (propertyType.IsAssignableFrom(typeof(decimal)))
                        v = ((NumericUpDown)map.Control).Value;
                    else if (propertyType.IsAssignableFrom(typeof(Int32)))
                        v = Convert.ToInt32(((NumericUpDown)map.Control).Value);
                }
                else if (map.Control is CheckedListBox)
                {
                    Type propertyType = t.GetProperty(map.Property).PropertyType;

                    CheckedListBox chks = (CheckedListBox)map.Control;
                    List<object> checkedItems = new List<object>();
                    foreach (object item in chks.CheckedItems)
                        checkedItems.Add(item);

                    if (propertyType.IsAssignableFrom(typeof(List<object>)))
                        v = checkedItems;
                    else if (propertyType.IsAssignableFrom(typeof(Array)))
                        v = checkedItems.ToArray();
                }
                else if (map.Control is ComboBox)
                {
                    ComboBox cbox = (ComboBox)map.Control;
                    if (cbox.DropDownStyle == ComboBoxStyle.DropDownList)
                        v = cbox.SelectedItem;
                    else
                        v = cbox.Text;
                }
                else if (map.Control is CheckBox)
                    v = ((CheckBox)map.Control).Checked;
                else if (map.Control is DateTimePicker)
                    v = ((DateTimePicker)map.Control).Value;
                else
                    throw new Exception("Value of control " + map.Control.Name + " is not retrieved. The control type is not supported.");

                t.InvokeMember(map.Property, System.Reflection.BindingFlags.SetProperty, null, entity, new object[] { v });
            }
        }
        /// <summary>
        /// 把一个对象中的数据应用到控件
        /// </summary>
        /// <param name="entity">保存数据的对象</param>
        /// <param name="maps">控件和属性的对应关系</param>
        public static void ApplyControlData(object entity, params ControlDataMap[] maps)
        {
            Type t = entity.GetType();
            foreach (ControlDataMap map in maps)
            {
                object v = t.InvokeMember(map.Property, System.Reflection.BindingFlags.GetProperty, null, entity, new object[0]);
                if (map.Control is TextBoxBase)
                    ((TextBoxBase)map.Control).Text = v == null ? "" : v.ToString();
                else if (map.Control is CheckBox)
                    ((CheckBox)map.Control).Checked = Convert.ToBoolean(v);
                else if (map.Control is NumericUpDown)
                    ((NumericUpDown)map.Control).Value = Convert.ToDecimal(v);
                else if (map.Control is CheckedListBox)
                {
                    CheckedListBox chks = (CheckedListBox)map.Control;
                    // 将对象中的数据copy到一个list中，方便后续查找
                    List<object> itemsToCheck = new List<object>();
                    if (v != null)
                    {
                        IEnumerator emr = ((IEnumerable)v).GetEnumerator();
                        while (emr.MoveNext())
                        {
                            if (emr.Current != null)
                                itemsToCheck.Add(emr.Current);
                        }
                    }

                    for (int i = 0; i <= chks.Items.Count - 1; i++)
                    {
                        object item = chks.Items[i];
                        if (item == null) continue;

                        object matched = itemsToCheck.Find(o => item.Equals(o));
                        if (matched == null)
                            chks.SetItemChecked(i, false);
                        else
                        {
                            itemsToCheck.Remove(matched); // 找到之后从list中移除，以减少list长度，提高后续查找效率
                            chks.SetItemChecked(i, true);
                        }
                    }
                }
                else if (map.Control is ComboBox)
                {
                    ComboBox cbox = (ComboBox)map.Control;
                    if (cbox.DropDownStyle == ComboBoxStyle.DropDownList)
                    {
                        IEnumerator emr = cbox.Items.GetEnumerator();
                        while (emr.MoveNext())
                        {
                            if (emr.Current == null) continue;
                            if (emr.Current.Equals(v))
                            {
                                cbox.SelectedItem = emr.Current;
                                break;
                            }
                        }
                    }
                    else
                        cbox.Text = v == null ? "" : v.ToString();
                }
                else if (map.Control is DateTimePicker)
                    ((DateTimePicker)map.Control).Value = (DateTime)v;
                else
                    throw new Exception("Value of control " + map.Control.Name + " is not set. The control type is not supported.");
            }
        }
    }
    /// <summary>
    /// 控件和属性对应关系
    /// </summary>
    public class ControlDataMap
    {
        public ControlDataMap(Control control, string property)
        {
            this.Control = control;
            this.Property = property;
        }
        /// <summary>
        /// 控件对象
        /// </summary>
        public Control Control { get; set; }
        /// <summary>
        /// 对应的属性
        /// </summary>
        public string Property { get; set; }
    }
}
